var my$ = function (Id) {
    return document.getElementById(Id)
};
//食物对象
(function () {
    var elements = [];
    //食物对象
    function Food(width,height,color){
        this.width = width||20;
        this.height = height||20;
        this.color = color||'green';
        this.x = 0;
        this.y = 0;
    }

    //获取随机食物坐标 坐标不能和身体重复
    Food.prototype.getRandFood = function(snackBody){
        this.x = Math.floor(Math.random()*(1 - map.offsetWidth / this.width - 1)+ map.offsetWidth / this.width + 1);
        this.y = Math.floor(Math.random()*(1 - map.offsetHeight / this.height - 1)+ map.offsetHeight / this.height + 1);

        if(snackBody){
            for (var i =0;i<snackBody.length;i++){
                if(this.x ==snackBody[i].x && this.y == snackBody[i].y){
                    this.getRandFood(snackBody);
                    break;
                }
            }
        }

    };

    //食物初始化  初始化时 不能出现在蛇身体里面
    Food.prototype.init = function (map,snackBody) {
        remove();
        //创建小盒子
        var div = document.createElement("div");
        //将div添加到map中
        map.appendChild(div);
        //设置样式
        div.style.width = this.width +"px";
        div.style.height = this.height +"px";
        div.style.backgroundColor = this.color;
        div.style.position = "absolute";
        //随机位置生成
        this.getRandFood(snackBody);
        div.style.left = (this.x * this.width - this.width/2) + 'px';
        div.style.top = (this.y  * this.height - this.height/2) + 'px';
        elements.push(div);
    };

    //删除全部对象
    function remove() {
        for (var i =0;i<elements.length;i++){
            elements[i].parentElement.removeChild(elements[i]);
            elements.splice(i,1);
        }
    }

    //将对象暴露给外部
    window.Food = Food
})();

//小蛇
(function () {
    var elements = [];
    //小蛇对象
    function Snack(width, height, direction) {
        this.width = width || 20;
        this.height = height || 20;
        this.direction = direction || 'right';
        this.beforeDirection = this.direction;
        this.body = [
            {x:3,y:2,'color':'red',},//头部
            {x:2,y:2,'color':'orange',},
            {x:1,y:2,'color':'orange',},
        ]
    }

    //初始化小蛇
    Snack.prototype.init = function (map) {
        remove();
        for (var i = 0; i < this.body.length; i++){
            var div = document.createElement("div");
            map.appendChild(div);
            div.style.width = this.width+"px";
            div.style.height = this.height +"px";
            div.style.backgroundColor = this.body[i].color;
            if(this.body[i].color=='red'){
                div.style.zIndex = 9;
            }
            div.style.borderRadius = "50%";
            div.style.position = "absolute";
            div.style.left =( this.body[i].x * this.width - this.width/2 ) + 'px';
            div.style.top = (this.body[i].y * this.height - this.height/2 )+ 'px';
            elements.push(div)
        }
    };

    //移动事件
    Snack.prototype.move = function (food,map) {
        //拿到蛇尾
        var index = this.body.length -1;
        //循环将蛇的每个部位 向前移动
        for (var i=index;i>0;i--){
            this.body[i].x = this.body[i-1].x;
            this.body[i].y = this.body[i-1].y;
        }

        //边界值
        var maxX = (map.offsetWidth )/this.width;
        var maxY = (map.offsetHeight )/this.height;

        //判断蛇头部坐标的位置
        switch(this.direction){
            case "right":
                this.body[0].x+=1;
                if(this.body[0].x>maxX)
                    this.body[0].x = 1;
                break;
            case "left":
                this.body[0].x-=1;
                if(this.body[0].x<=0)
                    this.body[0].x = maxX
                break;
            case "top":
                this.body[0].y-=1;
                if(this.body[0].y<=0)
                    this.body[0].y = maxY
                break;
            case "buttom":
                this.body[0].y+=1;
                if(this.body[0].y>maxY)
                    this.body[0].y = 1;
                break;
        }

        //判断蛇头的坐标
        var headX = this.body[0].x ;
        var headY = this.body[0].y;

        var foodX = food.x;
        var foodY = food.y;
        //头部和食物重合
        if (headX == foodX && headY ==foodY ){
            food.init(map,this.body);//重置食物
            var last = this.body[this.body.length-1];
            for(var i = 0;i<1;i++){
                this.body.push({
                    x:last.x,
                    y:last.y,
                    color:last.color,
                })
            }
        }
        //当前长度or得分
        my$("num1").innerHTML = this.body.length - 3;
    };

    function remove() {
        for (var i = 0; i < elements.length; i++) {
            elements[i].parentElement.removeChild(elements[i]);
        }
        elements.splice(0, elements.length);
    }

    window.Snack = Snack;
})();

//游戏对象
(function () {
    //将小蛇 食物，背景三个对象添加到游戏对象中
    function Game() {
        this.food = new Food();
        this.snack = new Snack();
        this.map = my$("map");

        //计算边界坐标
        this.maxX = this.map.offsetWidth / this.snack.width;
        this.maxY = this.map.offsetHeight / this.snack.height;
    }

//设置游戏规则
//1.不能碰壁
    Game.prototype.runSnack = function () {
        var that = this;
        //移动
        var timeId = setInterval(function(){

            this.snack.move(this.food,this.map);
            this.snack.init(this.map);

            //蛇头的坐标
            var headX = this.snack.body[0].x;
            var headY = this.snack.body[0].y;

            //不能穿身
            for (var i =1;i<this.snack.body.length;i++){
                item = this.snack.body[i];
                if(item.x == headX && item.y==headY){
                    clearInterval(timeId);
                   my$('msg').innerHTML = '你吃掉了你的身体';
                }
            }
            //不能穿墙
            // if(headX<0 || headX > this.maxX || headY<0 || headY > this.maxY){
            //     clearInterval(timeId);
            //     my$('msg').innerHTML = '你撞墙了';
            // }
            //把这个函数绑定在that指向上
        }.bind(that),200)
    };

    //移动一步
    Game.prototype.moveSnack = function () {
        this.snack.move(this.food,this.map);
        this.snack.init(this.map);
    };

//改变方向
    Game.prototype.keyDown = function () {
        var that = this;
        document.addEventListener("keydown",function(e){
            this.snack.beforeDirection = this.snack.direction;
            switch (e.keyCode){
                case 37://左
                    //如果当前方向不是右 则变向左成功
                    this.snack.beforeDirection !='right'?this.snack.direction = 'left':this.snack.direction = 'right';
                    break;
                case 38://上
                    //如果当前方向不是右 则变向左成功
                    this.snack.beforeDirection !='buttom'?this.snack.direction = 'top':this.snack.direction = 'buttom';
                    break;
                case 39://右
                    //如果当前方向不是右 则变向左成功
                    this.snack.beforeDirection !='left'?this.snack.direction = 'right':this.snack.direction = 'left';
                    break;
                case 40://下
                    //如果当前方向不是右 则变向左成功
                    this.snack.beforeDirection !='top'?this.snack.direction = 'buttom':this.snack.direction = 'top';
                    break;
            }
            // that.moveSnack()
        }.bind(that))
    };
//游戏初始化
    Game.prototype.init = function () {
        //显示食物和小蛇
        this.food.init(this.map);
        this.snack.init(this.map);
        //调用移动函数
        this.runSnack();
        this.keyDown(this.map);
    };

    //游戏刷新
    Game.prototype.refresh = function(){
        //清除小蛇和食物
        this.food = new Food();
        this.snack = new Snack();

        this.food.init(this.map);
        this.snack.init(this.map);
    };

    window.Game = Game
})();

//自动寻路
(function () {
    var openList = [];//寻路列表
    var closeList = [];//丢弃列表
    function wayFinding(gameObj){
        this.game = gameObj;
        // this.start = startCoordinates;
        // this.end = endCoordinates;
        // //将起始节点 加入 open列表中
        // openList.push(startCoordinates)
    }

    //开始寻路
    wayFinding.prototype.init = function () {
        var openList = this.lookFor();
        if(openList){
            var endItem = openList[openList.length-1];
            if(endItem.x == this.end.x && endItem.y == this.end.y){
                //找到路径了 开始逆推路径
                this.getUltimatelyPath(endItem);
            }else{
                console.error("搜索失败",error);
            }
        }else{
            //末日模式 尽可能的活下来
            // 1.不以搜寻食物为目的  检索当前路径 选择一条最长的路径来

            // 2.搜寻中 尝试当前未知能否抵挡食物的位置 能则切换到食物的位置
        }
    };

    //普通寻路模式
    wayFinding.prototype.lookFor = function(){
        //重置初始变量
        openList = [];
        closeList = [];
        //初始化 开始点和结束点
        this.start = Object.assign({},this.game.snack.body[0]);
        this.end = this.game.food;
        openList.push(this.start);
        console.log("开始寻路：",this.start.x+","+this.start.y,this.end.x+","+this.end.y);
        var searching = true;
        //如果open列表空 则搜索路径失败
        var error = 0;
        while (openList.length>0){
            if (error>100){
                console.log("启用末日模式，我大概会死掉了，尽可能的寻找空地，努力生存下来");
                return false;
            }
            error++;
            //从open列表中 取出一个 f 最小的节点
            this.present = getPresent();
            //加入close列表
            closeList.push(this.present);
            //计算当前节点可抵达的所有节点
            var AdjacentNode = getAdjacentNode(this.present);
            for (var i=0;i<AdjacentNode.length;i++){
                var item = AdjacentNode[i];
                if(hasCloseList(item)!==false){
                    continue;//丢弃
                }
                //如果是蛇身 需要丢弃
                if(hasSnackBody(item,this.game.snack.body)!==false){
                    continue;
                }
                //计算估计值
                f = this.getF(item);
                //判断是否存在 open 列表
                var index = hasOpenList(item);
                if(index!==false){
                    //如果存在open列表 则判断f值的大小
                    if(openList[index].f > f){
                        openList[index].f = f;
                        openList[index].parent = this.present
                    }
                }else{
                    item['f'] = f;
                    item['parent'] = this.present;//记录父节点
                    openList.push(item);//加入到openlist列表
                }
                //检查是否存在目标节点
                if(item.x == this.end.x && item.y == this.end.y){
                    searching = false;
                    break;
                }
            }
            //停止检索
            if(!searching){
                break;
            }
        }
        return openList;
    };

    //计算某个点的F估计值 F(n) = G(n) + H(n)
    wayFinding.prototype.getF = function (p) {
        // G(n)表示由起点到节点n的预估消耗
        var g = getDistance(this.start,p);
        // H(n)表示节点n到终点的估计消耗
        var h = getDistance(p,this.end);

        return g+h;//返回f
    }

    //检查是否是蛇身
    function hasSnackBody(p,snack) {
        for (var i =0;i<snack.length;i++){
            if(p.x == snack[i].x && p.y==snack[i].y){
                return i;
            }
        }
        return false
    }

    //检查某个节点是否存在于 closelist 列表
    function hasCloseList(p) {
        for (var i=0;i<closeList.length;i++){
            if(p.x==closeList[i].x && p.y==closeList[i].y){
                return i;
            }
        }
        return false;
    }

    //检查某个节点是否存在于 openlist 列表
    function hasOpenList(p) {
        for (var i=0;i<openList.length;i++){
            if(p.x==openList[i].x && p.y==openList[i].y){
                return i;
            }
        }
        return false;
    }

    //从open中获取一个f值最小的节点
    function getPresent(){
        if(openList.length==1){
            return openList[0]
        }
        var p = false;
        for (var i=0;i<openList.length;i++){
            //如果存在 closelist 列表 则跳过
            if(hasCloseList(openList[i])!==false){
                continue;
            }
            if (!p || p.f>openList[i].f){
                p = openList[i];
            }
        }
        return p
    };

    //获取俩点直接的距离
    function getDistance(p1,p2){
        return Math.abs(p1.x-p2.x)+Math.abs(p1.y-p2.y)
    }

    //得到某个节点的相邻节点  对应的就是 上下左右 四个节点
    function getAdjacentNode(p) {
        var AdjacentNodeList = [
            {x:p.x,y:p.y-1},//上
            {x:p.x,y:p.y+1},//下
            {x:p.x-1,y:p.y},//左
            {x:p.x+1,y:p.y},//右
        ];
        // var max
        //检查点是否超出边界，如果超出 需要做对应的转换
        for(var i = 0;i<AdjacentNodeList.length;i++){
            var item = AdjacentNodeList[i];
            //小于最小
            if(item.x <1){
                item.x = game.maxX;
            }
            //超出最大
            if(item.x > game.maxX){
                item.x = 1;
            }

            if(item.y <1){
                item.y = game.maxY;
            }
            //超出最大
            if(item.y > game.maxY){
                item.y = 1;
            }
        }

        return AdjacentNodeList;
    }

    //传入相邻俩点 计算移动方向
    function getDirection(p1,p2,oldDirection){
        var direction = '';
        // if(getDistance(p1,p2)!=1){
        //     return false;
        // }
        //禁止逆向移动
        if(p1.x == p2.x){
            //上下移动
            if(p1.y>p2.y){
                //上
                direction = oldDirection == 'buttom'? 'buttom': 'top';
            }else{
                //下
                direction = oldDirection == 'top'? 'top':  'buttom';
            }
        }else{
            //左右移动
            if(p1.x>p2.x){
                //左
                direction = oldDirection == 'right'? 'right':  'left';
            }else{
                //右
                direction = oldDirection == 'left'? 'left':  'right';
            }
        }
        return direction
    }

    //得到最终路径
    wayFinding.prototype.getUltimatelyPath = function(item) {
        var list = [];
        while (item.parent){
            list.unshift({
                x:item.x,
                y:item.y,
            });
            item = item.parent
        }
        //将起始点加入
        list.unshift({
            x:this.start.x,
            y:this.start.y,
        });
        //开始自动寻路
        this.autoRun(list);
    };

    //传入路径 开始自动寻路
    wayFinding.prototype.autoRun = function(pathList){
        var that = this;
        var oldHead = false;//历史头
        var timeId = setInterval(function(){
            var snackHead = that.game.snack.body[0];
            if (snackHead == oldHead){
                return ;//不操作
            }
            var isFinish = true;
            for (var i = 0;i<pathList.length-1;i++){
                var item = pathList[i];
                if(snackHead.x == item.x && snackHead.y == item.y){
                    oldHead = Object.assign({},snackHead);
                    //在列表中
                    isFinish = false;
                    //计算移动方向
                    var direction = getDirection(snackHead,pathList[i+1],that.game.snack.direction);
                    if(!direction){
                        isFinish = true;//路径出错 重新计算
                        console.log("路径出错，重新计算")
                    }else{
                        that.game.snack.direction = direction
                    }
                    break;
                }
            }
            if(isFinish){
                clearTimeout(timeId);//结束本次寻路
                //开始新的寻路
                that.init();
            }
        },100);
    };
    window.wayFinding = wayFinding;
})();

//调用游戏对象 实现效果
var game = new Game();
game.init();